package com.ld.admin.service.timedtask;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.quartz.TriggerUtils;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.SimpleTriggerContext;
import org.springframework.stereotype.Service;

import com.ld.admin.model.timedtask.SysTimedtaskModel;
import com.ld.admin.model.timedtask.SysTimedtaskUserInfo;
import com.ld.common.service.ProjectBasicService;
import com.ld.common.util.task.TaskManager;
import com.ld.shieldsb.common.core.model.Result;
import com.ld.shieldsb.common.core.reflect.ModelUtil;
import com.ld.shieldsb.common.web.util.Web;
import com.ld.shieldsb.common.web.util.WebUtil;
import com.ld.shieldsb.dao.model.PageNavigationBean;
import com.ld.shieldsb.dao.model.QueryModel;

/**
 * 
 * 定时任务服务类，@Service注解用于自动注入
 * 
 * @ClassName SysTimedtaskService
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2019年01月04日 14:29:47
 *
 */
@Service
public class SysTimedtaskService extends ProjectBasicService {

    // 用于子类覆盖，扩展doSearch方法中QueryModel的处理（标准queryModel处理完，查询进行前的处理）
    @Override
    protected QueryModel extendDealQuery(QueryModel queryModel) {
        // TODO Auto-generated method stub
//        queryModel.setCondition("     jobName='test' and (select * from (select(sleep(5)))Desn) and status!=? "); //测试sql注入
        return super.extendDealQuery(queryModel);
    }

    // 用于子类覆盖，扩展doSearch方法中PageNavigationBean的处理（查询完成后进行）
    @Override
    protected <T> PageNavigationBean<T> extendDealPageNavigationBean(PageNavigationBean<T> pageNavigationBean) {
        // TODO Auto-generated method stub
        return super.extendDealPageNavigationBean(pageNavigationBean);
    }

    // 删除方法子类扩展（删除完成后进行）
    @Override
    protected <T> boolean extendRemove(Boolean flag, Class<T> classOfT, String key, Object value, Integer status, Long userId) {
        // TODO Auto-generated method stub
        return flag;
    }

    @Override
    public <T> Result addOrUpdate(T modelBean, boolean update) {
        SysTimedtaskModel newModel = (SysTimedtaskModel) modelBean;
        if (!update) {
            newModel.setJobId("task_" + RandomStringUtils.randomAlphanumeric(8));
        }
        Result result = getExcuteTime(newModel.getCronExpression(), "", 1);
        if (!result.getSuccess()) {
            return result;
        }
        result = TaskManager.getInstance(newModel.getClassName());
        if (!result.getSuccess()) {
            return result;
        }
        return super.addOrUpdate(modelBean, update);
    }

    // addOrUpdate子类扩展（addOrUpdate完成后进行）
    protected <T> boolean extendAddOrUpdate(Boolean flag, T modelBean, boolean update, String key, Long userId) {
        SysTimedtaskModel newModel = (SysTimedtaskModel) modelBean;
        SysTimedtaskModel cacheModel = TaskManager.get(newModel.getJobId());
        if (cacheModel != null) {
            ModelUtil.coptyModel(newModel, cacheModel); // 更新缓存任务
        }
        return true;
    }

    // 启动/停止DAO操作前的业务操作
    @Override
    public <T> Result extendBeforeStartOrStop(Class<T> classOfT, String key, Object keyValue, int isStart) {
        SysTimedtaskModel model = (SysTimedtaskModel) getOne(classOfT, key, keyValue);
        Result result = new Result();
        result.setSuccess(false);
        SysTimedtaskUserInfo userInfo = new SysTimedtaskUserInfo(); // 用户信息
        userInfo.setUserId(Web.Util.getSessionUserId(request));
        userInfo.setUserName(Web.Util.getSessionUserName(request));
        userInfo.setIp(WebUtil.getIpAddr(request));
        String opearate = "停止";
        if (model != null) {
            try {
                if (isStart == 1) { // 启动
                    opearate = "启动";
                    SysTimedtaskModel cacheModel = TaskManager.get(model.getJobId());
                    if (cacheModel == null) { // 未注册的先注册
                        result = TaskManager.register(model, userInfo);
                        if (!result.getSuccess()) {
                            return result;
                        }
                    } else {
                        TaskManager.updateTask(model.getJobId(), model); // 已经注册的，则更新一下
                    }
                    result = TaskManager.start(model.getJobId(), userInfo);
                } else {
                    result = TaskManager.stop(model.getJobId(), userInfo);
                }
            } catch (Exception e) {
                log.error(opearate + "任务失败！", e);
            }
        }
        return result;
    }

    /**
     * 获取springcron的cron表达式后面N次的执行时间
     * 
     * @Title getExcuteTime
     * @author 吕凯
     * @date 2020年7月1日 上午8:08:07
     * @param cron
     *            表达式
     * @param numTimes
     *            执行次数
     * @return Result
     */
    public Result getExcuteTime(String cron, int numTimes) {
        return getExcuteTime(cron, "", numTimes);
    }

    /**
     * 
     * 获取cron表达式后面N次的执行时间
     * 
     * @Title getExcuteTime
     * @author 吕凯
     * @date 2020年7月1日 上午8:08:39
     * @param cron
     *            表达式
     * @param type
     *            类型quartz或者springcron【默认】
     * @param numTimes
     *            执行次数
     * @return Result
     */
    public Result getExcuteTime(String cron, String type, int numTimes) {
        Result result = new Result();
        result.setSuccess(false);
        if (StringUtils.isEmpty(cron)) {
            result.setMessage("cron表达式为空");
            return result;
//            throw new IllegalArgumentException("参数不能为空");
        }
        if (numTimes > 20) {
            numTimes = 20;
        }
        List<String> list = new ArrayList<>(numTimes);

        try {

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if ("quartz".equals(type)) {
                CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
                cronTriggerImpl.setCronExpression(cron);// 这里写要准备猜测的cron表达式
                List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, numTimes);// 这个是重点，一行代码搞定~~
                for (int i = 0; i < dates.size(); i++) {
                    list.add(dateFormat.format(dates.get(i)));
                }

            } else {

                CronTrigger t = new CronTrigger(cron);
                SimpleTriggerContext context = new SimpleTriggerContext();
                for (int i = 0; i < numTimes; i++) {
                    Date nextExecutionTime = t.nextExecutionTime(context);
                    context.update(nextExecutionTime, nextExecutionTime, nextExecutionTime);
                    list.add(dateFormat.format(nextExecutionTime));
                }
            }

            result.setSuccess(true);
            result.setData(list);
            if (list.size() == 0) {
                result.setMessage("没有符合条件的数据");
            }
        } catch (Exception e) {
            log.warn("cron表达式错误！", e);
            result.setMessage("表达式错误！" + e.getMessage());
        }
        return result;
    }
}
